package com.flowable.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.common.annotation.Log;
import com.common.core.controller.BaseController;
import com.common.core.domain.AjaxResult;
import com.common.core.domain.entity.SysDept;
import com.common.core.domain.entity.SysUser;
import com.common.core.domain.model.LoginUser;
import com.common.enums.BusinessType;
import com.common.utils.CollectionUtils;
import com.common.utils.SecurityUtils;
import com.common.utils.bean.BeanUtils;
import com.flowable.common.PageResult;
import com.flowable.common.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
import com.flowable.controller.oa.vo.UserSimpleBaseVO;
import com.flowable.convert.BpmTaskConvert;
import com.flowable.convert.task.BpmProcessInstanceConvert;
import com.flowable.domain.dto.FlowTaskDto;
import com.flowable.domain.instance.BpmApprovalDetailReqVO;
import com.flowable.domain.instance.BpmProcessInstancePageReqVO;
import com.flowable.domain.vo.BpmTaskRespVO;
import com.flowable.domain.vo.FlowQueryVo;
import com.flowable.domain.vo.FlowTaskVo;
import com.flowable.domain.vo.task.BpmTaskApproveReqVO;
import com.flowable.domain.vo.task.BpmTaskRejectReqVO;
import com.flowable.domain.vo.task.BpmTaskReturnReqVO;
import com.flowable.service.IFlowDefinitionService;
import com.flowable.service.IFlowInstanceService;
import com.flowable.service.IFlowTaskService;
import com.system.service.ISysDeptService;
import com.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import static com.common.utils.CollectionUtils.*;

/**
 * <p>工作流任务管理<p>
 *
 * @author Tony
 * @date 2021-04-03
 */
@Slf4j
@Api(tags = "工作流流程任务管理")
@RestController
@RequestMapping("/flowable/task")
public class FlowTaskController extends BaseController {

    @Autowired
    private IFlowTaskService flowTaskService;

    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private IFlowDefinitionService flowDefinitionService;

    @Autowired
    private IFlowInstanceService flowInstanceService;

    @ApiOperation(value = "我发起的流程", response = FlowTaskDto.class)
    @GetMapping(value = "/myProcess")
    public AjaxResult myProcess(FlowQueryVo queryVo) {
        return flowTaskService.myProcess(queryVo);
    }

    @GetMapping("/getUserProfile")
    public AjaxResult profile(String userName)
    {
        SysUser user = userService.selectUserByUserName(userName);
          if(user!=null) {
              return AjaxResult.success(BeanUtils.toBean(user, UserSimpleBaseVO.class));
          }
          else {
            return   AjaxResult.error("未找到此用户");
          }
    }
    @GetMapping("/my-page")
    @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中，进行调用")
    public AjaxResult getProcessInstanceMyPage(
            @Valid BpmProcessInstancePageReqVO pageReqVO) {

        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        PageResult<HistoricProcessInstance> pageResult = flowInstanceService.getProcessInstancePage(
                userId, pageReqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return success(PageResult.empty(pageResult.getTotal()));
        }

        // 拼接返回
        Map<String, List<Task>> taskMap = flowTaskService.getTaskMapByProcessInstanceIds(
                convertList(pageResult.getList(), HistoricProcessInstance::getId));
        Map<String, ProcessDefinition> processDefinitionMap = flowDefinitionService.getProcessDefinitionMap(
                convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
//        Map<String, BpmCategoryDO> categoryMap = categoryService.getCategoryMap(
//                convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
        return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult,
                processDefinitionMap, taskMap, null, null));
    }

    @ApiOperation(value = "取消申请", response = FlowTaskDto.class)
    @Log(title = "取消申请", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/stopProcess")
    public AjaxResult stopProcess(@RequestBody FlowTaskVo flowTaskVo) {
        return flowTaskService.stopProcess(flowTaskVo);
    }

    @ApiOperation(value = "撤回流程", response = FlowTaskDto.class)
    @Log(title = "撤回流程", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/revokeProcess")
    public AjaxResult revokeProcess(@RequestBody FlowTaskVo flowTaskVo) {
        return flowTaskService.revokeProcess(flowTaskVo);
    }

    @ApiOperation(value = "获取待办列表", response = FlowTaskDto.class)
    @GetMapping(value = "/todoList")
    public AjaxResult todoList(FlowQueryVo queryVo) {
        return flowTaskService.todoList(queryVo);
    }

    @ApiOperation(value = "根据流程定义获取待办列表", response = FlowTaskDto.class)
    @GetMapping(value = "/todoListbyKey")
    public AjaxResult todoListBydefKey(FlowQueryVo queryVo) {
        return flowTaskService.todoListBydefKey(queryVo);
    }

    @ApiOperation(value = "获取已办任务", response = FlowTaskDto.class)
    @GetMapping(value = "/finishedList")
    public AjaxResult finishedList(FlowQueryVo queryVo) {
        return flowTaskService.finishedList(queryVo);
    }


    @ApiOperation(value = "流程历史流转记录", response = FlowTaskDto.class)
    @GetMapping(value = "/flowRecord")
    public AjaxResult flowRecord(String procInsId, String deployId) {
        return flowTaskService.flowRecord(procInsId, deployId);
    }

    @ApiOperation(value = "根据任务ID查询挂载的表单信息")
    @GetMapping(value = "/getTaskForm")
    public AjaxResult getTaskForm(String taskId) {
        return flowTaskService.getTaskForm(taskId);
    }


    @ApiOperation(value = "流程初始化表单", response = FlowTaskDto.class)
    @GetMapping(value = "/flowFormData")
    public AjaxResult flowFormData(String deployId) {
        return flowTaskService.flowFormData(deployId);
    }

    @ApiOperation(value = "获取流程变量", response = FlowTaskDto.class)
    @GetMapping(value = "/processVariables/{taskId}")
    public AjaxResult processVariables(@ApiParam(value = "流程任务Id") @PathVariable(value = "taskId") String taskId) {
        return flowTaskService.processVariables(taskId);
    }

    @ApiOperation(value = "审批任务")
    @Log(title = "审批任务", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/complete")
    public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) {
        return flowTaskService.complete(flowTaskVo);
    }

    @ApiOperation(value = "审批任务")
    @Log(title = "审批任务", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/completeTask")
    public AjaxResult completeTask(@RequestBody BpmApprovalDetailReqVO bpmApprovalDetailReqVO) {
         flowTaskService.completeTask(bpmApprovalDetailReqVO);
        return success(true);
    }

    @ApiOperation(value = "审批任务")
    @Log(title = "审批任务", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/approveTask")
    public AjaxResult  approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        flowTaskService.approveTask(user.getUserId(), reqVO);
        return success(true);
    }

    @ApiOperation(value = "驳回任务")
    @Log(title = "驳回任务", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/reject")
    public AjaxResult taskReject(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.taskReject(flowTaskVo);
        return AjaxResult.success();
    }

    @PostMapping("/rejecttask")
    @Operation(summary = "不通过任务")
    public AjaxResult rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        flowTaskService.rejectTask(sysUser.getUserId(), reqVO);
        return success(true);
    }

    @ApiOperation(value = "退回任务")
    @Log(title = "退回任务", businessType = BusinessType.UPDATE)
    @PostMapping(value = "/return")
    public AjaxResult taskReturn(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.taskReturn(flowTaskVo);
        return AjaxResult.success();
    }
    @ApiOperation(value = "芋道退回任务")
    @PutMapping("/return-task")
    @Operation(summary = "退回任务芋道", description = "用于【流程详情】的【退回】按钮")
    public AjaxResult returnTask(@Valid @RequestBody BpmTaskReturnReqVO reqVO) {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        flowTaskService.returnTask(sysUser.getUserId(), reqVO);
        return success(true);
    }

    @GetMapping("/list-by-return")
    @Operation(summary = "获取所有可退回的节点", description = "用于【流程详情】的【退回】按钮")
    @Parameter(name = "taskId", description = "当前任务ID", required = true)
    public AjaxResult getTaskListByReturn(@RequestParam("taskId") String taskId) {
        List<UserTask> userTaskList = flowTaskService.getUserTaskListByReturn(taskId);
        return AjaxResult.success(convertList(userTaskList, userTask -> // 只返回 id 和 name
        {
            BpmTaskRespVO bpmTaskRespVO = new BpmTaskRespVO();
             bpmTaskRespVO.setName(userTask.getName());
            bpmTaskRespVO.setTaskDefinitionKey(userTask.getId());
            return bpmTaskRespVO;
        }));
    }

    @ApiOperation(value = "获取所有可回退的节点")
    @PostMapping(value = "/returnList")
    public AjaxResult findReturnTaskList(@RequestBody FlowTaskVo flowTaskVo) {
        return flowTaskService.findReturnTaskList(flowTaskVo);
    }

    @ApiOperation(value = "删除任务")
    @Log(title = "删除任务", businessType = BusinessType.DELETE)
    @DeleteMapping(value = "/delete")
    public AjaxResult delete(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.deleteTask(flowTaskVo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "认领/签收任务")
    @PostMapping(value = "/claim")
    public AjaxResult claim(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.claim(flowTaskVo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "取消认领/签收任务")
    @PostMapping(value = "/unClaim")
    public AjaxResult unClaim(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.unClaim(flowTaskVo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "委派任务")
    @PostMapping(value = "/delegateTask")
    public AjaxResult delegate(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.delegateTask(flowTaskVo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "任务归还")
    @PostMapping(value = "/resolveTask")
    public AjaxResult resolveTask(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.resolveTask(flowTaskVo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "转办任务")
    @PostMapping(value = "/assignTask")
    public AjaxResult assign(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.assignTask(flowTaskVo);
        return AjaxResult.success();
    }

    @PostMapping(value = "/addMultiInstanceExecution")
    @ApiOperation(value = "多实例加签")
    public AjaxResult addMultiInstanceExecution(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.addMultiInstanceExecution(flowTaskVo);
        return AjaxResult.success("加签成功");
    }

    @PostMapping(value = "/deleteMultiInstanceExecution")
    @ApiOperation(value = "多实例减签")
    public AjaxResult deleteMultiInstanceExecution(@RequestBody FlowTaskVo flowTaskVo) {
        flowTaskService.deleteMultiInstanceExecution(flowTaskVo);
        return AjaxResult.success("减签成功");
    }

    @ApiOperation(value = "获取下一节点")
    @PostMapping(value = "/nextFlowNode")
    public AjaxResult getNextFlowNode(@RequestBody FlowTaskVo flowTaskVo) {
        return flowTaskService.getNextFlowNode(flowTaskVo);
    }

    @ApiOperation(value = "流程发起时获取下一节点")
    @PostMapping(value = "/nextFlowNodeByStart")
    public AjaxResult getNextFlowNodeByStart(@RequestBody FlowTaskVo flowTaskVo) {
        return flowTaskService.getNextFlowNodeByStart(flowTaskVo);
    }

    /**
     * 生成流程图
     *
     * @param processId 任务ID
     */
    @GetMapping("/diagram/{processId}")
    public void genProcessDiagram(HttpServletResponse response,
                                  @PathVariable("processId") String processId) {
        InputStream inputStream = flowTaskService.diagram(processId);
        OutputStream os = null;
        BufferedImage image = null;
        try {
            image = ImageIO.read(inputStream);
            response.setContentType("image/png");
            os = response.getOutputStream();
            if (image != null) {
                ImageIO.write(image, "png", os);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取流程执行节点
     *
     * @param procInsId 流程实例编号
     * @param procInsId 任务执行编号
     */
    @GetMapping("/flowViewer/{procInsId}/{executionId}")
    public AjaxResult getFlowViewer(@PathVariable("procInsId") String procInsId,
                                    @PathVariable("executionId") String executionId) {
        return flowTaskService.getFlowViewer(procInsId, executionId);
    }
    @GetMapping("/isAuditor")
    Boolean IsAuditor(String UserId,String procInsId){
        return flowTaskService.IsAuditor(UserId,procInsId);
    }

    /**
     * 流程节点信息
     *
     * @param procInsId 流程实例id
     * @return
     */
    @GetMapping("/flowXmlAndNode")
    public AjaxResult flowXmlAndNode(@RequestParam(value = "procInsId", required = false) String procInsId,
                                     @RequestParam(value = "deployId", required = false) String deployId) {
        return flowTaskService.flowXmlAndNode(procInsId, deployId);
    }

    @GetMapping("/list-by-process-instance-id")
    @Operation(summary = "获得指定流程实例的任务列表", description = "包括完成的、未完成的")
    @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true)
    public AjaxResult getTaskListByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId)
    {
        List<HistoricTaskInstance> taskList = flowTaskService.getTaskListByProcessInstanceId(processInstanceId, true);
        if (CollUtil.isEmpty(taskList)) {
            return success(Collections.emptyList());
        }
        // 拼接数据
        Set<Long> userIds = convertSetByFlatMap(taskList, task -> Stream.of(parseLong(task.getAssignee()), parseLong(task.getOwner())));
        List<SysUser>users=userService.listByIds(userIds);
        Map<Long, SysUser> userMap = CollectionUtils.convertMap(users, SysUser::getUserId);
        List<SysDept> sysDepts=deptService.listByIds(convertSet(userMap.values(), SysUser::getDeptId));
        Map<Long, SysDept> deptMap=CollectionUtils.convertMap(sysDepts, SysDept::getDeptId);
        List<BpmTaskRespVO> bpmTaskRespVOS= BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, userMap, deptMap);
        return  AjaxResult.success(bpmTaskRespVOS);
    }

    /**
     * 流程节点表单
     *
     * @param taskId 流程任务编号
     * @return
     */
    @GetMapping("/flowTaskForm")
    public AjaxResult flowTaskForm(@RequestParam(value = "taskId", required = false) String taskId) throws Exception {
        return flowTaskService.flowTaskForm(taskId);
    }


    /**
     * 流程节点信息
     *
     * @param procInsId 流程实例编号
     * @param elementId 流程节点编号
     * @return
     */
    @GetMapping("/flowTaskInfo")
    public AjaxResult flowTaskInfo(@RequestParam(value = "procInsId") String procInsId,
                                   @RequestParam(value = "elementId") String elementId){
        return flowTaskService.flowTaskInfo(procInsId,elementId);
    }

    public static Long parseLong(String str) {
        return StrUtil.isNotEmpty(str) ? Long.valueOf(str) : null;
    }

}
